import json

from django.shortcuts import render
from django.views import View
from django.http import JsonResponse
from django_redis import get_redis_connection

from goods.models import SKU
from meiduo_mall.utils.cookiesecret import CookieSecret


class CartsView(View):

    def get(self, request):
        """查询/展示购物车"""
        # 后续未来方便业务数据组织，从redis或cookie读取的购物车数据，统一组成字典数据
        cart_dict = {}  # 购物车字典数据，{1: {'count': 5, 'selected': true}}

        user = request.user

        if user.is_authenticated:
            conn = get_redis_connection('carts')
            # 1. 读取购物车商品数量，hash数据
            redis_carts = conn.hgetall(f'carts_{user.id}')

            # 2. 读取购物车选中状态，集合数据
            redis_selected = conn.smembers(f'selected_{user.id}')

            # 3. 把redis购物车数据转化成购物车字典数据
            sku_ids = redis_carts.keys()
            for sku_id in sku_ids:
                cart_dict[int(sku_id)] = {
                    'count': int(redis_carts[sku_id]),
                    'selected': sku_id in redis_selected
                }

        else:
            cookie_str = request.COOKIES.get('carts')
            if cookie_str:
                cart_dict = CookieSecret.loads(cookie_str)

        # 读取mysql获取sku商品的详细信息，组织响应参数
        sku_ids = cart_dict.keys()  # [1, 2]
        cart_skus = []
        for sku_id in sku_ids:
            sku = SKU.objects.get(pk=sku_id)
            cart_skus.append({
                'id': sku.id,
                'name': sku.name,
                'price': sku.price,
                'default_image_url': sku.default_image.url,
                'count': cart_dict[sku_id]['count'],
                'selected': cart_dict[sku_id]['selected']
            })

        return JsonResponse({'code': 0,
                             'errmsg': 'ok',
                             'cart_skus': cart_skus
                             }, status=200, json_dumps_params={'ensure_ascii': False})

    def post(self, request):
        """添加购物车"""
        data = json.loads(request.body.decode())

        sku_id = data.get('sku_id')
        count = data.get('count')
        selected = data.get('selected', True)  # 默认勾选

        if not all([sku_id, count]):
            return JsonResponse({'code': 400, 'errmsg': '缺少必要参数'}, status=400, json_dumps_params={'ensure_ascii': False})

        try:
            sku = SKU.objects.get(pk=sku_id, is_launched=True)
        except Exception as e:
            return JsonResponse({'code': 400, 'errmsg': '商品不存在或已下架'}, status=400, json_dumps_params={'ensure_ascii': False})

        # 3. 业务处理
        user = request.user

        # 3.1 登录  ---> 存入redis
        if user.is_authenticated:
            conn = get_redis_connection('carts')
            p = conn.pipeline()

            # 如果当前sku_id在hash对象里面，需要把count累加
            # p.hmset(f'carts_{user.id}', {sku_id: count})  # 存hash对象：商品和数量
            p.hincrby(f'carts_{user.id}', sku_id, count)  # 该函数会自动累加count,不存在则新增

            if selected:
                p.sadd(f'selected_{user.id}', sku_id)  # 存集合：记录选中状态
            else:
                p.srem(f'selected_{user.id}', sku_id)  # 未选中，删除

            p.execute()
            return JsonResponse({'code': 0, 'errmsg': 'ok'}, status=200, json_dumps_params={'ensure_ascii': False})

        # 3.2 未登录 --> 存入cookie
        else:
            # （1）当前请求cookie里面是否有购物车数据
            cookie_str = request.COOKIES.get('carts')  # carts是存入cookie的购物车数据的key
            if cookie_str:
                # 有购物车数据,需解密
                cart_dict = CookieSecret.loads(cookie_str)

            else:
                # 没有购物车数据
                cart_dict = {}

            # （2）追加当前新增的商品
            if sku_id in cart_dict:
                # 把数量累加
                cart_dict[sku_id]['count'] += count
                cart_dict[sku_id]['selected'] = selected
            else:
                cart_dict[sku_id] = {
                    'count': count,
                    'selected': selected,
                }

        # （3）把最新的cookie购物车字典数据，编码成字符串写入cookie
        cookie_str = CookieSecret.dumps(cart_dict)
        response = JsonResponse({'code': 0, 'errmsg': 'ok'}, status=200, json_dumps_params={'ensure_ascii': False})
        response.set_cookie('carts', cookie_str, max_age=14 * 3600 * 24)

        return response

    def put(self, request):
        """修改购物车"""

        data = json.loads(request.body.decode())
        sku_id = data.get('sku_id')
        count = data.get('count')
        selected = data.get('selected', True)

        # 构建响应参数
        cart_sku = {
            'sku_id': sku_id,
            'count': count,
            'selected': selected
}

        if not all([sku_id, count]):
            return JsonResponse({'code': 400, 'errmsg': '缺少必要参数'}, status=400, json_dumps_params={'ensure_ascii': False})

        try:
            sku = SKU.objects.get(pk=sku_id, is_launched=True)
        except Exception as e:
            return JsonResponse({'code': 400, 'errmsg': '商品不存在或已下架'}, status=400, json_dumps_params={'ensure_ascii': False})

        user = request.user

        if user.is_authenticated:
            # 已登录，修改redis购物车
            conn = get_redis_connection('carts')
            p = conn.pipeline()
            # 1. 修改商品数量
            p.hset(f'carts_{user.id}', sku_id, count)
            # 2. 修改选中状态
            if selected:
                p.sadd(f'selected_{user.id}', sku_id)  # 存集合：记录选中状态
            else:
                p.srem(f'selected_{user.id}', sku_id)  # 未选中，删除
            p.execute()

            return JsonResponse({'code': 0,
                                 'errmsg': 'ok',
                                 'cart_sku': cart_sku,
                                 }, status=200, json_dumps_params={'ensure_ascii': False})

        else:
            # 未登录，修改cookie购物车
            cookie_str = request.COOKIES.get('carts')

            if cookie_str:
                cart_dict = CookieSecret.loads(cookie_str)
            else:
                cart_dict = {}

            if sku_id in cart_dict:
                cart_dict[sku_id]['count'] = count
                cart_dict[sku_id]['selected'] = selected

            cookie_str = CookieSecret.dumps(cart_dict)
            response = JsonResponse({'code': 0, 'errmsg': 'ok', 'cart_sku': cart_sku}, status=200, json_dumps_params={'ensure_ascii': False})
            response.set_cookie('carts', cookie_str)

            return response

    def delete(self, request):
        """删除购物车"""
        data = json.loads(request.body.decode())
        sku_id = data.get('sku_id')

        if not sku_id:
            return JsonResponse({'code': 400, 'errmsg': '缺少必要参数'}, status=400, json_dumps_params={'ensure_ascii': False})

        try:
            sku = SKU.objects.get(pk=sku_id)
        except Exception as e:
            return JsonResponse({'code': 400, 'errmsg': '商品不存在或已下架'}, status=400, json_dumps_params={'ensure_ascii': False})

        # 业务数据处理

        user = request.user

        if user.is_authenticated:
            conn = get_redis_connection('carts')

            # （1）把sku_id从hash对象中删除
            conn.hdel(f'carts_{user.id}', sku_id)
            # （2）把sku_id从集合中删除
            conn.srem(f'selected_{user.id}', sku_id)

            return JsonResponse({'code': 0,
                                 'errmsg': 'ok',
                                 }, status=200, json_dumps_params={'ensure_ascii': False})

        else:
            # 1. 读取cookie购物车字典数据
            cookit_str = request.COOKIES.get('carts')
            if cookit_str:
                cart_dict = CookieSecret.loads(cookit_str)
            else:
                cart_dict = {}

            # 2. 删除指定sku_id
            # del cart_dict[sku_id]  # 方式一
            if sku_id in cart_dict:
                cart_dict.pop(sku_id)

            # 3. 重新加密设置在cookie中
            cookie_str = CookieSecret.dumps(cart_dict)
            response = JsonResponse({'code': 0, 'errmsg': 'ok'}, status=200, json_dumps_params={'ensure_ascii': False})
            response.set_cookie('carts', cookie_str)

            return response


class CartsSelectAllView(View):
    """购物车全选接口"""

    def put(self, request):
        data = json.loads(request.body.decode())
        selected = data.get('selected')  # 没有传是None

        # 判断selected类型，必须是bool类型（True和False）
        if not isinstance(selected, bool):
            return JsonResponse({'code': 400, 'errmsg': '参数有误'}, status=400, json_dumps_params={'ensure_ascii': False})

        user = request.user

        if user.is_authenticated:
            # 登录，把redis购物车全部商品选中
            conn = get_redis_connection('carts')

            redis_carts = conn.hgetall(f'carts_{user.id}')

            sku_ids = redis_carts.keys()

            if selected:
                conn.sadd(f'selected_{user.id}', *sku_ids)
            else:
                conn.srem(f'selected_{user.id}', *sku_ids)

            return JsonResponse({'code': 0, 'errmsg': 'ok'}, status=200, json_dumps_params={'ensure_ascii': False})

        else:
            # 未登录，把cookie购物车全部商品选中
            cookit_str = request.COOKIES.get('carts')
            if cookit_str:
                cart_dict = CookieSecret.loads(cookit_str)
            else:
                cart_dict = {}

            for sku_id in cart_dict.keys():
                cart_dict[sku_id]['selected'] = selected

            cookie_str = CookieSecret.dumps(cart_dict)
            response = JsonResponse({'code': 0, 'errmsg': 'ok'}, status=200, json_dumps_params={'ensure_ascii': False})
            response.set_cookie('carts', cookie_str)

            return response


class CartsSimpleView(View):
    """简单购物车"""

    def get(self, request):

        user = request.user

        conn = get_redis_connection('carts')

        cart_dict = {}  # 用于后续记录redis或者cookie中读取的购物车--> {1: {'count': 5, 'selected': true}....}
        if user.is_authenticated:
            redis_carts = conn.hgetall(f'carts_{user.id}')
            redis_selected = conn.smembers(f'selected_{user.id}')

            # 构建统一约定好的购物车字典数据  ——> 只处理选中的
            sku_ids = redis_carts.keys()
            for sku_id in sku_ids:
                if sku_id in redis_selected:
                    cart_dict[int(sku_id)] = {
                        'count': int(redis_carts[sku_id]),
                        'selected': True,
                    }
        else:
            cookie_str = request.COOKIES.get('carts')
            if cookie_str:
                cart_dict = CookieSecret.loads(cookie_str)

            # keys()返回是迭代器对象，循环中还是的cart_dict对象，所以在循环中删除可能会报错。
            # 解决方法：强转成列表
            sku_ids = list(cart_dict.keys())
            for sku_id in sku_ids:
                if not cart_dict[sku_id]['selected']:  # 当前sku商品在购物车中未选中
                    cart_dict.pop(sku_id)

        sku_ids = cart_dict.keys()  # 一定都是选中的商品

        cart_skus = []
        for sku_id in sku_ids:
            sku = SKU.objects.get(pk=sku_id)
            cart_skus.append({
                'id': sku.id,
                'name': sku.name,
                'count': cart_dict[sku_id]['count'],
                'default_image_url': sku.default_image.url
            })

        return JsonResponse({'code': 0, 'errmsg': 'ok',
                             'cart_skus': cart_skus
                             }, status=200, json_dumps_params={'ensure_ascii': False})













